//package SM2CertGen;

import java.io.*;
import java.io.FileWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.*;
import java.text.SimpleDateFormat;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.Collections;
import java.util.AbstractMap; // 如果使用SimpleEntry则需要，但当前代码中没有使用
import org.bouncycastle.util.Arrays;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
//import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.io.*;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.DistributionPointName;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.ReasonFlags;
import org.bouncycastle.asn1.x509.CertificatePolicies;
import org.bouncycastle.asn1.x509.PolicyInformation;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.x509.UserNotice;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.ASN1EncodableVector;

import org.bouncycastle.cert.jcajce.*;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.X509CRLHolder;
import org.bouncycastle.cert.X509v2CRLBuilder;

import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;

public class SM2CertGen {
    // SCT执行命令参数
    private static final List<String> SCT_CMD = java.util.Arrays.asList(
        "java",
        "-cp",
        ".;JarBC18181/*",
        "SCTGenerator"
    );

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static void main(String[] args) throws Exception {

        /* ---------- 1. 生成根 CA ---------- */
        KeyPair caKP = genSM2KP();
        X509Certificate caCert = buildRootCACert(caKP);
        
        /* ---------- 2. 生成子证书 B ---------- */
        KeyPair bKP = genSM2KP();
        X509Certificate bCert = buildChildCert(caCert, caKP.getPrivate(), bKP.getPublic(),
                "CN=127.0.0.1,O=Hello,C=CN");

        /* ---------- 3. 生成证书吊销列表 B ---------- */
        //基本CRL
        X509CRLHolder caCRLbase = buildRootCACRLbase(caCert, caKP.getPrivate(), Collections.emptyList());
        //增量CRL
        X509CRLHolder caCRLdelta = buildRootCACRLdelTa(caCert, caKP.getPrivate(), Collections.emptyList());

        /* ---------- 3. 写出文件 ---------- */
        writePEM("ca.crt", caCert);
        writePrivatePEM("ca.key", caKP.getPrivate());
        writePEM("b.crt", bCert);
        writePrivatePEM("b.key", bKP.getPrivate());
        System.out.println("已生成 ca.crt/ca.key, b.crt/b.key。");

        writePEM("ca.crl", caCRLbase);
        writePEM("ca_delta.crl", caCRLdelta);
        System.out.println("已生成 ca.crl  ca_delta.crl");

        // 新增这行：按顺序合并证书 (b.crt -> ca.crt)
        writeCertificateChain("chain.crt", "b.crt", "ca.crt"); // 顺序：终端证书在前，根证书在后
        System.out.println("已生成证书链 chain.crt");

    }

    /* ---------- 工具方法 ---------- */

    private static KeyPair genSM2KP() throws GeneralSecurityException {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");
        kpg.initialize(new org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec("sm2p256v1"));
        return kpg.generateKeyPair();
    }



    /**
     * 创建SCT列表扩展
     */
    private static DEROctetString createSCTListExtension() throws Exception {
            // 将十六进制字符串转换为字节数组
            byte[] sctBytes = hexStringToByteArray(
                "0165"+"0075"+
                "00dd26d7aa874093121a03c3e0c766d4cc0eaa0b2f448d35c6c794ba994c69086b"+
                "000001988441b55f"+
                "00000403"+
                "00463044022035601cc12590abcc616defcc8bed71568a1beb3f655fadf3dc6f8f3fc3892281022069b945df6fe3adfae597174c76c19a6520a7a39c346786866f429febd7a3ddad007500448d35c6c794ba994c69086bf098a71cafd2723add26d7aa874093121a03c3e0000001988441b55f000004030046304402200b8695f480fbbff47355472c6d1f4e32b7d44a5ecddf2c9b8bbe89a06d27eb290220429852acf6c3c2cd052cbb359cb05b07c4c6f5e127e3631f8186c919d0851ca300750012f14e34bd53724c840619c38f3f7a13f8e7b56287889c6d300584ebe586263a000001988441b55f00000403004630440220070e34b4935036bbc1c44efc82661bf0522e227d9e75380e37b448d16fa507e102200ef186b55e116dad8b70ff19e8d2dccb3e90e34ee88d51b5952cb1ce66f13265"
            ); 

            //执行外部SCT服务
            Process process = null;
            //使用ProcessBuilder执行外部SCT服务
            ProcessBuilder pb = new ProcessBuilder(SCT_CMD);
            pb.redirectErrorStream(true); // 合并错误流到标准输出
            process = pb.start();
            process.waitFor();
            // 检查SCT文件是否存在
            Path sctPath = Paths.get("sctlist.sct");
            if (!Files.exists(sctPath)) {
                return new DEROctetString(sctBytes);
            }
            
            try {
                // 读取sct文件内容（二进制格式）
                byte[] sctResponse = Files.readAllBytes(sctPath);
                return new DEROctetString(Arrays.copyOfRange(sctResponse, 4, sctResponse.length));
           } catch (IOException e) {
                System.err.println("SCT错误: " + e.getMessage());
            } 
        return new DEROctetString(sctBytes);
    }

    /**
     * 将十六进制字符串转换为字节数组
     */
    private static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                             + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }


    /**
     * 生成根CA的基本CRL
     * @param caCert 根CA证书
     * @param caPrivateKey 根CA私钥
     * @param revokedCerts 要吊销的证书列表（序列号和原因）
     * @return X509CRLHolder对象
     */
    private static X509CRLHolder buildRootCACRLbase(
            X509Certificate caCert, 
            PrivateKey caPrivateKey,
            List<Map.Entry<BigInteger, Integer>> revokedCerts) throws Exception {

            //默认数据 已吊销证书序列号serial
            /*
                吊销原因reason：

                序列号: 1  | 理由码: 0  | 含义: 未指定原因
                序列号: 2  | 理由码: 1  | 含义: 密钥泄露
                序列号: 3  | 理由码: 2  | 含义: CA私钥泄露
                序列号: 4  | 理由码: 3  | 含义: 从属关系变更
                序列号: 5  | 理由码: 4  | 含义: 证书被取代
                序列号: 6  | 理由码: 5  | 含义: 停止操作
                序列号: 7  | 理由码: 6  | 含义: 证书暂停
                序列号: 8  | 理由码: 8  | 含义: 从CRL移除
                序列号: 9  | 理由码: 9  | 含义: 特权撤销

            默认使用 0 (unspecified)：除非有明确需求
            临时吊销用 6 (certificateHold)：允许后续恢复证书
            恢复证书用 8 (removeFromCRL)：在增量 CRL 中使用
            安全事件用 1 (keyCompromise)：密钥泄露时强制吊销
            */
            revokedCerts = List.of(
                Map.entry(BigInteger.valueOf(1), 0),
                Map.entry(BigInteger.valueOf(1), 1),
                Map.entry(BigInteger.valueOf(2), 2),
                Map.entry(BigInteger.valueOf(3), 3),
                Map.entry(BigInteger.valueOf(4), 4),
                Map.entry(BigInteger.valueOf(5), 5),
                Map.entry(BigInteger.valueOf(6), 6),
                Map.entry(BigInteger.valueOf(7), 7),
                Map.entry(BigInteger.valueOf(8), 8),
                Map.entry(BigInteger.valueOf(9), 9),
                Map.entry(BigInteger.valueOf(1), 10)
            );

        // 获取根CA的主题名称
        X500Name issuer = new JcaX509CertificateHolder(caCert).getSubject();
        
        // 设置CRL的有效期
        Date thisUpdate = new Date();  // 当前时间
        Date nextUpdate = new Date(System.currentTimeMillis() + 7 * 24 * 3600 * 1000L); // 7天后
        
        // 创建CRL构建器
        X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuer, thisUpdate);
        crlBuilder.setNextUpdate(nextUpdate);
        
        // 添加吊销的证书
        for (Map.Entry<BigInteger, Integer> entry : revokedCerts) {
            BigInteger serial = entry.getKey();
            int reason = entry.getValue();
            crlBuilder.addCRLEntry(serial, thisUpdate, reason);
        }
        
        // 添加CRL扩展
        crlBuilder.addExtension(Extension.authorityKeyIdentifier, false,
                new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(caCert));
        
        crlBuilder.addExtension(Extension.cRLNumber, false,
                new CRLNumber(BigInteger.valueOf(1)));

        // 创建签名器
        ContentSigner signer = new JcaContentSignerBuilder("SM3withSM2")
                .setProvider("BC")
                .build(caPrivateKey);
        
        // 生成CRL
        return crlBuilder.build(signer);
    }
    /**
     * 生成根CA的增量CRL
     * @param caCert 根CA证书
     * @param caPrivateKey 根CA私钥
     * @param revokedCerts 要吊销的证书列表（序列号和原因）
     * @return X509CRLHolder对象
     */
    private static X509CRLHolder buildRootCACRLdelTa(
            X509Certificate caCert, 
            PrivateKey caPrivateKey,
            List<Map.Entry<BigInteger, Integer>> revokedCerts) throws Exception {

            //默认数据 已吊销证书序列号serial
            /*
                吊销原因reason：

                序列号: 1  | 理由码: 0  | 含义: 未指定原因
                序列号: 2  | 理由码: 1  | 含义: 密钥泄露
                序列号: 3  | 理由码: 2  | 含义: CA私钥泄露
                序列号: 4  | 理由码: 3  | 含义: 从属关系变更
                序列号: 5  | 理由码: 4  | 含义: 证书被取代
                序列号: 6  | 理由码: 5  | 含义: 停止操作
                序列号: 7  | 理由码: 6  | 含义: 证书暂停
                序列号: 8  | 理由码: 8  | 含义: 从CRL移除
                序列号: 9  | 理由码: 9  | 含义: 特权撤销

            默认使用 0 (unspecified)：除非有明确需求
            临时吊销用 6 (certificateHold)：允许后续恢复证书
            恢复证书用 8 (removeFromCRL)：在增量 CRL 中使用
            安全事件用 1 (keyCompromise)：密钥泄露时强制吊销
            */
            revokedCerts = List.of(
                Map.entry(BigInteger.valueOf(1), 1),
                Map.entry(BigInteger.valueOf(6), 8)

            );

        // 获取根CA的主题名称
        X500Name issuer = new JcaX509CertificateHolder(caCert).getSubject();
        
        // 设置CRL的有效期
        Date thisUpdate = new Date();  // 当前时间
        Date nextUpdate = new Date(System.currentTimeMillis() + 7 * 24 * 3600 * 1000L); // 7天后
        
        // 创建CRL构建器
        X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuer, thisUpdate);
        crlBuilder.setNextUpdate(nextUpdate);
        
        // 添加吊销的证书
        for (Map.Entry<BigInteger, Integer> entry : revokedCerts) {
            BigInteger serial = entry.getKey();
            int reason = entry.getValue();
            crlBuilder.addCRLEntry(serial, thisUpdate, reason);
        }
        
        // 添加CRL扩展
        crlBuilder.addExtension(Extension.authorityKeyIdentifier, false,
                new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(caCert));
        //增量CRL的编码
        crlBuilder.addExtension(Extension.cRLNumber, false,
                new CRLNumber(BigInteger.valueOf(6)));

        //增量CRL专用扩展（指定基本CRL编号1）
        crlBuilder.addExtension(Extension.deltaCRLIndicator, false, new CRLNumber(BigInteger.valueOf(1)));

        // 创建签名器
        ContentSigner signer = new JcaContentSignerBuilder("SM3withSM2")
                .setProvider("BC")
                .build(caPrivateKey);
        
        // 生成CRL
        return crlBuilder.build(signer);
    }

    /**
     * 创建证书策略扩展
     * 包含策略OID和可选的证书实践声明(CPS)
     */
    private static CertificatePolicies createCertificatePoliciesExtension() {
         // 定义证书策略 OID
        String CERT_POLICY_URL = "https://www.example.com/cps"; // 证书实践声明URL
        // 创建策略限定符（可选）
        org.bouncycastle.asn1.x509.PolicyQualifierInfo qualifier = new org.bouncycastle.asn1.x509.PolicyQualifierInfo(
            new ASN1ObjectIdentifier("1.3.6.1.5.5.7.2.1"), // CPS限定符OID
            new DERIA5String(CERT_POLICY_URL) // 实践声明URL
        );
        // 创建 UserNotice 对象
        UserNotice userNotice = new UserNotice(
            null, // noticeRef（通知引用），这里设置为 null
            CERT_POLICY_URL // explicitText（显式文本）
        );
        // 创建策略限定符（可选）
        org.bouncycastle.asn1.x509.PolicyQualifierInfo qualifier_nonice = new org.bouncycastle.asn1.x509.PolicyQualifierInfo(
            new ASN1ObjectIdentifier("1.3.6.1.5.5.7.2.2"), // CPS限定符OID
            userNotice.toASN1Primitive() // 用户通告
        );  

        // 创建策略信息 CPS实践声明URL
        PolicyInformation policyInfo = new PolicyInformation(
            new ASN1ObjectIdentifier("2.23.140.1.1"), // 策略OID
            new DERSequence(qualifier) // 限定符序列
        );
        // 创建策略信息 用户通告
        PolicyInformation policyInfo2 = new PolicyInformation(
            new ASN1ObjectIdentifier("2.23.140.1.3"), // 策略OID
            new DERSequence(qualifier_nonice) // 限定符序列
        );

        // 创建 CertificatePolicies 扩展
        PolicyInformation[] policiesArray = new PolicyInformation[] { policyInfo, policyInfo2 };    
        return new CertificatePolicies(policiesArray);
    }

private static X509Certificate buildRootCACert(KeyPair kp) throws Exception {
    X500Name subject = new X500Name("CN=SM2 Root CA,O=MyOrg,C=CN");
    BigInteger serial = BigInteger.valueOf(10);//System.currentTimeMillis()
    Date notBefore = new Date(System.currentTimeMillis() - 24 * 3600 * 1000L);
    Date notAfter  = new Date(System.currentTimeMillis() + 365L * 24 * 3600 * 1000L);

    ContentSigner signer = new JcaContentSignerBuilder("SM3withSM2")
            .setProvider("BC").build(kp.getPrivate());

    X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
            subject, serial, notBefore, notAfter,
            subject, kp.getPublic())

            //密钥用法
            .addExtension(org.bouncycastle.asn1.x509.Extension.keyUsage, true,
                    new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign))
            //基本约束
            .addExtension(org.bouncycastle.asn1.x509.Extension.basicConstraints, true,
                    new BasicConstraints(true)) //false :最终实体 |true：CA
            
            //使用者密钥标识符|授权密钥标识符
            .addExtension(org.bouncycastle.asn1.x509.Extension.subjectKeyIdentifier, false, new JcaX509ExtensionUtils().createSubjectKeyIdentifier(kp.getPublic()))
            .addExtension(org.bouncycastle.asn1.x509.Extension.authorityKeyIdentifier, false, new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(kp.getPublic()))

            //扩展CRL分发点
            .addExtension(org.bouncycastle.asn1.x509.Extension.cRLDistributionPoints, false, new DLSequence(new DistributionPoint[] {
                //基本CRL
                new DistributionPoint(
                    new DistributionPointName(
                        new GeneralNames(new GeneralName(GeneralName.uniformResourceIdentifier, "http://anqikeji.picp.net/ca.crl"))
                    ),
                    null, null
                ),
                //增量CRL
                new DistributionPoint(
                    new DistributionPointName(
                        new GeneralNames(new GeneralName(GeneralName.uniformResourceIdentifier, "http://anqikeji.picp.net/ca_delta.crl"))
                    ),//Reasons: Remove From CRL (0x8)
                    null, null
                )
            }))

            //扩展证书策略
            .addExtension(org.bouncycastle.asn1.x509.Extension.certificatePolicies, false, createCertificatePoliciesExtension())

            //扩展SCT列表
            .addExtension(new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.4.2"), 
                          false, 
                          createSCTListExtension())

            //扩展授权信息访问
            .addExtension(org.bouncycastle.asn1.x509.Extension.authorityInfoAccess, false, new AuthorityInformationAccess(new AccessDescription[] {
                new AccessDescription(AccessDescription.id_ad_ocsp, new GeneralName(GeneralName.uniformResourceIdentifier, "http://anqikeji.picp.net/ocsp")),
                new AccessDescription(AccessDescription.id_ad_caIssuers, new GeneralName(GeneralName.uniformResourceIdentifier, "http://anqikeji.picp.net/ca.crt"))
            }));

    return new JcaX509CertificateConverter().setProvider("BC")
            .getCertificate(builder.build(signer));
}

private static X509Certificate buildChildCert(
        X509Certificate caCert, PrivateKey caKey,
        PublicKey childPub, String childDN) throws Exception {

    X500Name issuer = new JcaX509CertificateHolder(caCert).getSubject();
    X500Name subject = new X500Name(childDN);
    BigInteger serial = BigInteger.valueOf(11);//System.currentTimeMillis()
    Date notBefore = new Date(System.currentTimeMillis() - 24 * 3600 * 1000L);
    Date notAfter  = new Date(System.currentTimeMillis() + 180L * 24 * 3600 * 1000L);

    ContentSigner signer = new JcaContentSignerBuilder("SM3withSM2")
            .setProvider("BC").build(caKey);

    X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
            issuer, serial, notBefore, notAfter,
            subject, childPub)

            //密钥用法
            .addExtension(org.bouncycastle.asn1.x509.Extension.keyUsage, true,
                    new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment))
            
            //基本约束
            .addExtension(org.bouncycastle.asn1.x509.Extension.basicConstraints, true,
                    new BasicConstraints(false)) //false :最终实体 |true：CA

            //使用者密钥标识符|授权密钥标识符
            .addExtension(org.bouncycastle.asn1.x509.Extension.subjectKeyIdentifier, false, new JcaX509ExtensionUtils().createSubjectKeyIdentifier(childPub))
            .addExtension(org.bouncycastle.asn1.x509.Extension.authorityKeyIdentifier, false, new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(caCert))
            
            //扩展CRL分发点
            .addExtension(org.bouncycastle.asn1.x509.Extension.cRLDistributionPoints, false, new DLSequence(new DistributionPoint[] {
                //基本CRL
                new DistributionPoint(
                    new DistributionPointName(
                        new GeneralNames(new GeneralName(GeneralName.uniformResourceIdentifier, "http://anqikeji.picp.net/ca.crl"))
                    ),
                    null, null
                ),
                //增量CRL
                new DistributionPoint(
                    new DistributionPointName(
                        new GeneralNames(new GeneralName(GeneralName.uniformResourceIdentifier, "http://anqikeji.picp.net/ca_delta.crl"))
                    ),//Reasons: Remove From CRL (0x8)
                    null, null
                )
            }))

            //扩展证书策略
            .addExtension(org.bouncycastle.asn1.x509.Extension.certificatePolicies, false, createCertificatePoliciesExtension())
            
            //扩展SCT列表
            .addExtension(new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.4.2"), 
                          false, 
                          createSCTListExtension())
            
            //扩展授权信息访问
            .addExtension(org.bouncycastle.asn1.x509.Extension.authorityInfoAccess, false, new AuthorityInformationAccess(new AccessDescription[] {
                new AccessDescription(AccessDescription.id_ad_ocsp, new GeneralName(GeneralName.uniformResourceIdentifier, "http://anqikeji.picp.net/ocsp")),
                new AccessDescription(AccessDescription.id_ad_caIssuers, new GeneralName(GeneralName.uniformResourceIdentifier, "http://anqikeji.picp.net/ca.crt"))
            }));
    return new JcaX509CertificateConverter().setProvider("BC")
            .getCertificate(builder.build(signer));
}

    private static void writePEM(String fileName, Object obj) throws IOException {
        try (JcaPEMWriter w = new JcaPEMWriter(new FileWriter(fileName))) {
            w.writeObject(obj);
        }
    }

    private static void writePrivatePEM(String fileName, PrivateKey key) throws IOException {
        try (JcaPEMWriter w = new JcaPEMWriter(new FileWriter(fileName))) {
            w.writeObject(key);
        }
    }

    // 在您的代码中添加此方法
    private static void writeCertificateChain(String fileName, String... certFiles) throws Exception {
        try (FileWriter writer = new FileWriter(fileName)) {
            for (String certFile : certFiles) {
                // 读取每个证书文件内容
                String content = new String(Files.readAllBytes(Paths.get(certFile)));
                // 写入chain文件（保留原始格式）
                writer.write(content);
                // 确保每个证书之间有换行分隔
                if (!content.endsWith("\n")) writer.write("\n");
            }
        }
    }
}